﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using System.Xml.Linq;

using Azure.Logger;

namespace Azure.Core
{
    public interface ISerializer : IDisposable
    {
        void Serialize(AzNewDataBlock data);

        void Serialize(List<AzNewDataBlock> data);
    }

    internal class AzCache<T> : IDisposable
    {
        private int _capacity = 4;
        private List<T> _cacher;
        private List<T> _cacherBackup;
        private Object _lock = new Object();
        private AutoResetEvent _dumpCacheEvent = new AutoResetEvent(true);

        public int Capacity { get { return _capacity; } }

        public delegate void CacheFullDelegate();
        public delegate void CacheDisposeDelegate(List<T> remainData);

        public event CacheDisposeDelegate CacheDisposeEvent;
        public event CacheFullDelegate CacheFullEvent;

        public AzCache(int capacity)
        {
            _capacity = capacity;
            _cacher = new List<T>(_capacity);
        }

        public AzCache()
        {
            _cacher = new List<T>(_capacity);
        }

        //可能是NULL
        public List<T> GetCachedData()
        {
            return _cacherBackup;
        }

        public void Dispose()
        {
            lock (_lock)
            {
                //发出事件,将剩余数据推送出去,等待处理完毕
                if (CacheDisposeEvent != null)
                    CacheDisposeEvent(_cacher);

                _cacher = null;
                _cacherBackup = null;
            }
        }

        //外部用来通知Cache，他已经dump完了
        public void NotifyDumpCompleted()
        {
            _dumpCacheEvent.Set();
        }

        public void Cache(T cachee)
        {
            if (cachee == null)
                return;

            lock (_lock)
            {
                //可能被其他线程Dispose
                if (_cacher == null)
                    return;

                _cacher.Add(cachee);

                //缓存满了进行交换
                if (_cacher.Count == _capacity)
                {
                    //先检查是否之前的DUMP还没有完成，如果没有完成则等待
                    _dumpCacheEvent.WaitOne();

                    //将满的列表转到backup上
                    _cacherBackup = _cacher;
                    //创建一个新，继续进行缓存
                    _cacher = new List<T>(_capacity);

                    //通知订阅者，缓存满了
                    if (CacheFullEvent != null)
                        CacheFullEvent();
                }
            }
        }

        public void Cache(List<T> cachee)
        {
            if (cachee == null)
                return;

            lock (_lock)
            {
                //可能被其他线程Dispose
                if (_cacher == null)
                    return;

                if (_cacher.Count + cachee.Count <= _capacity)
                    _cacher.AddRange(cachee);
                //缓存会满
                else
                {
                    //将缓存填满
                    int addCount = _capacity - _cacher.Count;
                    int i = 0;
                    for (; i < addCount; i++)
                    {
                        _cacher.Add(cachee[i]);
                    }

                    //至此，缓存满了
                    //先检查是否之前的DUMP还没有完成，如果没有完成则等待
                    _dumpCacheEvent.WaitOne();

                    //将满的列表转到backup上
                    _cacherBackup = _cacher;
                    //创建一个新，继续进行缓存
                    _cacher = new List<T>(_capacity);

                    //通知订阅者，缓存满了
                    if (CacheFullEvent != null)
                        CacheFullEvent();

                    //将剩余的记录继续添加到新的缓存中
                    for (; i < cachee.Count; i++)
                    {
                        _cacher.Add(cachee[i]);
                    }
                }//end if (_cacher.Count + cachee.Count <= _capacity)
            }
        }
    }

    internal class AzXMLSerializer : AzSerializerBase
    {
        private FileInfo _fi = null;
        private FileStream _fs = null;
        private StreamWriter _sw = null;

        public AzXMLSerializer(String path) : base()
        {
            if (path == null)
            {
                AzLogger.Error("AzXMLSerializer.ctor XML文件路径为null");
                throw new NullReferenceException();
            }

            //创建文件
            try
            {
                _fi = new FileInfo(path);

                while (_fi.Exists)
                {
                    AzLogger.Warn("AzXMLSerializer.ctor XML文件" + path + "已经存在，自动扩展名字");
                    path = path + "-" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss") + ".xml";
                    AzLogger.Warn("AzXMLSerializer.ctor XML文件新名字为" + path);
                    _fi = new FileInfo(path);
                }

                _fs = _fi.Create();
            }
            catch (Exception ex)
            {
                AzLogger.Error("AzXMLSerializer.ctor 创建文件信息" + path + "失败", ex);
                throw;
            }

            //创建输出流
            try
            {
                _sw = new StreamWriter(_fs);
                //输出XML文件头
                _sw.WriteLine(@"<?xml version=""1.0"" encoding=""utf-8""?>");
            }
            catch (Exception ex)
            {
                AzLogger.Error("AzXMLSerializer.ctor 创建输出流失败", ex);
                //关闭之前打开的文件流
                _fs.Close();

                try
                {
                    //删除该文件
                    _fi.Delete();
                }
                catch (Exception e)
                {
                    AzLogger.Error("AzXMLSerializer.ctor 删除文件" + path + "失败", e);
                    throw;
                }
                //交给外部处理该异常
                throw;
            }
        }

        public override void Dispose()
        {
            base.Dispose();

            if (_sw != null)
            {
                _sw.Close();
                _sw = null;
            }

            if (_fs != null)
            {
                _fs.Close();
                _fs = null;
            }

            _fi = null;
        }

        protected override void DumpData(Object state)
        {
            //可能在其他线程被DIPOSE
            if (_sw == null)
                return;

            List<AzNewDataBlock> data = state as List<AzNewDataBlock>;
            //将数据输出到XML中
            foreach (AzNewDataBlock block in data)
            {
                _sw.WriteLine("<" + block.DataSource + ">");

                foreach (AzNewDataBlock.AzDataCell row in block.DataCells.Values)
                {
                    _sw.WriteLine("\t<" + row.ColumnName + ">" + row.CellValue.ToString() + "</" + row.ColumnName + ">");
                }

                _sw.WriteLine("</" + block.DataSource + ">");
            }

            _sw.Flush();

            //必须call base的
            base.DumpData(state);
        }
    }

    internal class AzSerializerBase : ISerializer
    {
        private AzCache<AzNewDataBlock> _cache = null;
        private Object _lockDump = new Object();
        private Object _lockCache = new Object();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <exception cref="Exception">注意有异常出没</exception>
        public AzSerializerBase()
        {
            _cache = new AzCache<AzNewDataBlock>();
            _cache.CacheFullEvent += this.OnCacheFullEvent;
            _cache.CacheDisposeEvent += this.OnCacheDisposeEvent;
        }

        public virtual void Dispose()
        {
            lock (_lockCache)
            {
                if (_cache != null)
                {
                    _cache.Dispose();

                    _cache.CacheFullEvent -= this.OnCacheFullEvent;
                    _cache.CacheDisposeEvent -= this.OnCacheDisposeEvent;
                    _cache = null;
                }
            }
        }

        public virtual void Serialize(AzNewDataBlock data)
        {
            lock (_lockCache)
            {
                if (_cache != null)
                    _cache.Cache(data);
            }
        }

        public virtual void Serialize(List<AzNewDataBlock> data)
        {
            lock (_lockCache)
            {
                if (_cache != null)
                    _cache.Cache(data);
            }
        }

        private void OnCacheFullEvent()
        {
            //将任务Queue到线程池中做处理,然后就返回，不阻塞Queue数据的抓取线程
            ThreadPool.QueueUserWorkItem(DumpData, _cache.GetCachedData());
        }

        private void OnCacheDisposeEvent(List<AzNewDataBlock> remainData)
        {
            //不使用线程池处理剩余的数据
            DumpData(remainData);
        }

        protected virtual void DumpData(Object state)
        {
            //防止DISPOSE调用的DUMPDATA比之前刚QUEUE到队列中的DUMPDATA稍快完成而造成null exception
            lock (_lockDump)
            {
                //通知Cache完成了输出工作
                if (_cache != null)
                    _cache.NotifyDumpCompleted();
            }
        }
    }
}
